package br.com.massai.model.entity;

import java.io.UnsupportedEncodingException;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.List;
import java.util.Map;

import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.EnumType;
import javax.persistence.Enumerated;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.JoinTable;
import javax.persistence.ManyToMany;
import javax.persistence.NamedQueries;
import javax.persistence.NamedQuery;
import javax.persistence.SequenceGenerator;
import javax.persistence.Table;
import javax.persistence.Transient;

import org.hibernate.annotations.Fetch;
import org.hibernate.annotations.FetchMode;
import org.hibernate.annotations.LazyCollection;
import org.hibernate.annotations.LazyCollectionOption;

import br.com.massai.view.enums.Role;
import br.com.massai.view.enums.Status;

/**
 * @author diogo
 *
 */
@Entity
@Table(name = "COLLABORATOR")
@NamedQueries({
	@NamedQuery(name = "Collaborator.find", query = "SELECT c FROM Collaborator C"),
	@NamedQuery(name = "Collaborator.duplicate", query = "SELECT COUNT(c) FROM Collaborator c WHERE LOWER(c.username) = LOWER(:username)"),
	@NamedQuery(name = "Collaborator.count", query = "SELECT COUNT(c) FROM Collaborator c"),
	@NamedQuery(name = "Collaborator.login", query = "SELECT c FROM Collaborator c WHERE LOWER(c.username) = LOWER(:username) AND c.password =:password AND c.active =:active")
})
public class Collaborator extends GenericEntity {

	private static final long serialVersionUID = -162857292787341060L;

	@Id
	@SequenceGenerator(name = "seqCollaborator", sequenceName = "seq_collaborator", allocationSize = 1)
	@GeneratedValue(generator = "seqCollaborator", strategy = GenerationType.SEQUENCE)
	private Long id;

	@Column(name = "USERNAME", length = 20, nullable = false, unique = true, columnDefinition = "VARCHAR(20)")
	private String username;

	@Column(name = "PASSWORD", nullable = false, columnDefinition = "TEXT")
	private String password;

	@Column(name = "NAME_COLLABORATOR", nullable = false, columnDefinition = "VARCHAR(150)")
	private String nameCollaborator;

	@Column(name = "EMAIL", nullable = true, columnDefinition = "VARCHAR(255)")
	private String email;

	@Enumerated(EnumType.STRING)
	@Column(name = "ACTIVE", nullable = false, columnDefinition = "CHAR(1)")
	private Status active;

	@Enumerated(EnumType.STRING)
	@Column(name = "ROLE", columnDefinition = "CHAR(1)")
	private Role role;

	@LazyCollection(LazyCollectionOption.FALSE)
	@ManyToMany(cascade = CascadeType.MERGE)
	@Fetch(FetchMode.SUBSELECT)
	@JoinTable(name = "USER_ACTION", 
		joinColumns = @JoinColumn(name = "ID_USER", referencedColumnName = "ID"), 
		inverseJoinColumns = @JoinColumn(name = "ID_ACTION", referencedColumnName = "ID"))
	private List<Action> actions;
	
	@Transient
	private List<Url> urls;

	@Transient
	private AccessControl accessControl;
	
	public Collaborator() {
		this.active = Status.A;
		this.role = Role.C;
//		this.setPassword(Collaborator.DEFAULT_PASSWORD);
	}

	public Collaborator(String username, String password){
		super();
		this.username = username;
		this.setPassword(password);
	}

	private String encodedSHA256(String str){
		String encript = null;
		try {
			MessageDigest digest = MessageDigest.getInstance("SHA-256");
			byte messageDigest[] = digest.digest(str.getBytes("UTF-8"));
			StringBuilder hexStr = new StringBuilder();
			for(byte b : messageDigest)
				hexStr.append(String.format("%02X", 0xFF & b));
			encript = hexStr.toString();

		} catch (NoSuchAlgorithmException e) {
			e.printStackTrace();
		} catch (UnsupportedEncodingException e) {
			e.printStackTrace();
		}
		return encript;
	}

	public Map<String,Object> getParameters() {
		super.clearParameters();

		if(this.nameCollaborator != null && !this.nameCollaborator.trim().isEmpty()){
			super.addClauseWhere("LOWER(c.nameCollaborator) LIKE LOWER(:nameCollaborator)", ConditionType.AND);
			super.addParameters("nameCollaborator", "%" + this.nameCollaborator + "%");
		}

		if(this.username != null && !this.username.trim().isEmpty()){
			super.addClauseWhere("LOWER(c.username) LIKE LOWER(:username)", ConditionType.AND);
			super.addParameters("username", "%" + this.username + "%");
		}

		if(this.email != null && !this.email.trim().isEmpty()){
			super.addClauseWhere("LOWER(c.email) LIKE LOWER(:email)", ConditionType.AND);
			super.addParameters("email", "%" + this.email + "%");
		}

		return super.getParameters();
	}

	@Override
	public boolean equals(Object obj) {
		if(obj == null) return false;
		if(obj instanceof Collaborator)
			if(((Collaborator)obj).getId().equals(this.id)) return true;

		return false;
	}

	public Long getId() {
		return id;
	}

	public void setId(Long id) {
		this.id = id;
	}

	public String getUsername() {
		return username;
	}

	public void setUsername(String username) {
		this.username = username;
	}

	public String getPassword() {
		return password;
	}

	public void setPassword(String password) {
		if(password != null && !password.trim().isEmpty())
			this.password = this.encodedSHA256(password.trim());
	}

	public String getEmail() {
		return email;
	}

	public void setEmail(String email) {
		this.email = email;
	}

	public Status getActive() {
		return active;
	}

	public void setActive(Status active) {
		this.active = active;
	}

	public Role getRole() {
		return role;
	}

	public void setRole(Role role) {
		this.role = role;
	}

	public String getNameCollaborator() {
		return nameCollaborator;
	}

	public void setNameCollaborator(String nameCollaborator) {
		this.nameCollaborator = nameCollaborator;
	}

	public AccessControl getAccessControl() {
		return accessControl;
	}

	public void setAccessControl(AccessControl accessControl) {
		this.accessControl = accessControl;
	}

	public List<Action> getActions() {
		return actions;
	}

	public void setActions(List<Action> actions) {
		this.actions = actions;
	}

	public List<Url> getUrls() {
		return urls;
	}

	public void setUrls(List<Url> urls) {
		this.urls = urls;
	}
}
